// Thud - a dynamic object-oriented language
// Copyright (C) 2009,2010 David H. Hovemeyer <david.hovemeyer@gmail.com>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

/*
 * VM_Object.h
 *
 *  Created on: Jan 2, 2010
 *      Author: dhovemey
 */

#ifndef VM_OBJECT_H_
#define VM_OBJECT_H_

#include <cassert>
#include <cstdint>

typedef uint16_t ClassId;

// Note: VM_Interpreter must ensure that these class ids are used
const ClassId CLASS_ID_CLASS = 0;
const ClassId CLASS_ID_NIL = 1;
const ClassId CLASS_ID_STRING = 2;
const ClassId CLASS_ID_SYMBOL = 3;
const ClassId CLASS_ID_INT32 = 4;
const ClassId CLASS_ID_BOOLEAN = 5;
const ClassId CLASS_ID_CHARACTER = 6;

const ClassId CLASS_MAX_CLASSES = 65535;

const uint16_t OBJECT_FLAG_ALLOCED = 1;
const uint16_t OBJECT_FLAG_MARK    = 2;

union VM_ObjectField {
	void *p;
	int32_t ival;
};

class VM_Object {
private:
	ClassId m_clsId; // what class this object belongs to
	uint16_t m_flags;
	union {
		VM_ObjectField *m_fields;
		VM_Object *m_nextInFreelist; // for use by VM_Arena
	};

	VM_Object(const VM_Object &);
	VM_Object& operator=(const VM_Object &);

public:
	VM_Object(ClassId clsId, uint16_t numFields);
	virtual ~VM_Object();

	ClassId getClassId() const { return m_clsId; }

	void *getMagicPtr() { return m_fields[0].p; }
	void setMagicPtr(void *p_) { m_fields[0].p = p_; }

	int32_t getMagicInt() { return m_fields[0].ival; }
	void setMagicInt(int32_t i) { m_fields[0].ival = i; }

	VM_Object *getField(int fieldIndex) { return (VM_Object *) m_fields[fieldIndex].p; }
	void setField(int fieldIndex, VM_Object *obj) { m_fields[fieldIndex].p = obj; }

	void alloced() {
		assert(!isFlagSet(OBJECT_FLAG_ALLOCED));
		m_flags |= OBJECT_FLAG_ALLOCED;
	}

	void mark() {
		assert(isFlagSet(OBJECT_FLAG_ALLOCED));
		m_flags |= OBJECT_FLAG_MARK;
	}

	void unmark() {
		m_flags &= ~(OBJECT_FLAG_MARK);
	}

	bool isFlagSet(uint16_t flag) const {
		return (m_flags & flag) == flag;
	}

	void clearFlags() {
		m_flags = 0;
	}

	VM_Object *getNextInFreelist() {
		assert(!isFlagSet(OBJECT_FLAG_ALLOCED));
		return m_nextInFreelist;
	}

	void setNextInFreelist(VM_Object *nextInFreelist) {
		assert(!isFlagSet(OBJECT_FLAG_ALLOCED));
		m_nextInFreelist = nextInFreelist;
	}
};

#endif /* VM_OBJECT_H_ */
